module.exports = (function(){
  function _Vnode(tagName,args){
    args = args || {};
    this.parentNode = null;
    this.childNodes = [];
    this.nextSibling = null;
    this.firstChild = null;
    this.lastChild = null;
    this._id_ = a.zIndex();
    this.attributes = {};
    this.tagName = tagName;
    this.nodeType = 1;
    this.nodeValue = null;
    for(var key in args) this[key] = args[key];
    this.getAttribute = function(name){
      return this.attributes[name];
    }
    this.setAttribute = function(name,value){
      this.attributes[name] = value;
    }
    this.removeAttribute = function(name){
      var attributes = {};
      for(var key in this.attributes) if(key != name) attributes[key] = this.attributes[key];
      this.attributes = attributes;
    }
    this.events = {};
    this.addEventListener = function(type,func,useCapture){
      if(!this.events[type]) this.events[type] = {};
      var name = func.toString().match(/^function\s*([\S]*)\(/)[1] || 'default';
      this.events[type][name] = {func:func,useCapture:useCapture};
    }
    this.removeEventListener = function(type,func){
      if(this.events[type]){
        if(!func) {
          this.events[type] = null;
        }else{
          var name = func.toString().match(/^function\s*([\S]*)\(/)[1];
          if(name && this.events[type][name]) this.events[type][name] = null;
        }
      }
    }
    this.attributesToString = function(){
      if(this.nodeType === 3){
        return this.nodeValue;
      }else{
        var rc = '<' + this.tagName + ' ';
        for(var key in this.attributes) {
          if(this.attributes[key] != undefined) {
            if(this.attributes[key] === true){
              rc += key + ' ';
            }else{
              rc += key + '="' + this.attributes[key] + '" ';
            }
          }
        }
        return rc.replace(/ $/,'') + '>';
      }
    }
    this.toString = function(before){
      if(typeof before == 'function') before.call(this);
      if(this.nodeType === 3){
        return this.nodeValue;
      }else{
        var innerHTML = '';
        for(var i = 0; i < this.childNodes.length; i ++) innerHTML += this.childNodes[i].toString(before);
        return this.attributesToString() + innerHTML + '</' + this.tagName + '>';
      }
    }
    this.appendChild = function(vnode){
      if(vnode.parentNode) vnode.parentNode.removeChild(vnode);
      vnode.parentNode = this;
      var prev = this.childNodes[this.childNodes.length - 1];
      if(prev) prev.nextSibling = vnode;
      vnode.previousSibling = prev;
      vnode.nextSibling = null;
      this.childNodes.push(vnode);
      if(this.childNodes.length == 1) this.firstChild = vnode;
      this.lastChild = vnode;
    }
    this.removeChild = function(vnode){
      var index = null;
      for(var i = 0; i < this.childNodes.length; i ++) if(this.childNodes[i]._id_ == vnode._id_) index = i;
      if(index >= 0){
        if(vnode.previousSibling) vnode.previousSibling.nextSibling = vnode.nextSibling;
        if(vnode.nextSibling) vnode.nextSibling.previousSibling = vnode.previousSibling;
        this.childNodes.splice(index,1);
        vnode.parentNode = null;
        vnode.nextSibling = null;
        vnode.previousSibling = null;
      }
    }
    this.insertBefore = function(vnode,existingvnode){
      if(!existingvnode){
        this.appendChild(vnode);
      }else{
        var index = null;
        for(var i = 0; i < this.childNodes.length; i ++) if(this.childNodes[i]._id_ == existingvnode._id_) index = i;
        if(index >= 0){
          if(vnode.parentNode) vnode.parentNode.removeChild(vnode);
          if(existingvnode.previousSibling){
            existingvnode.previousSibling.nextSibling = vnode;
            vnode.previousSibling = existingvnode.previousSibling;
          }
          vnode.nextSibling = existingvnode;
          existingvnode.previousSibling = vnode;
          vnode.parentNode = this;
          this.childNodes.splice(index,0,vnode);
        }
      }
    }
    this.replaceChild = function(newVnode,oldVnode){
      this.insertBefore(newVnode,oldVnode);
      this.removeChild(oldVnode);
    }
    this.vnodeTree = function(){
      var rc = {
        attributes:this.attributes,
        tagName:this.tagName,
        nodeType:this.nodeType,
        nodeValue:this.nodeValue,
        childNodes:[]
      }
      for(var i = 0; i < this.childNodes.length; i ++) rc.childNodes.push(this.childNodes[i].vnodeTree());
      return rc;
    }
    this.cloneNode = function(deep){
      return _Vnode.parseVnodeTree(this.vnodeTree());
    }
  }
  _Vnode.parseVnodeTree = function(obj){
    var rc = new _Vnode(obj.tagName);
    rc.attributes = obj.attributes;
    rc.tagName = obj.tagName;
    rc.nodeType = obj.nodeType;
    rc.nodeValue = obj.nodeValue;
    rc.childNodes = [];
    var previousSibling = null;
    for(var i = 0; i < obj.childNodes.length; i ++){
      var childNode = _Vnode.parseVnodeTree(obj.childNodes[i]);
      if(previousSibling) previousSibling.nextSibling = childNode;
      if(i == 0) rc.firstChild = childNode;
      if(i == obj.childNodes.length - 1) rc.lastChild = childNode;
      childNode.parentNode = rc;
      childNode.previousSibling = previousSibling;
      rc.childNodes.push(childNode);
      previousSibling = childNode;
    }
    return rc;
  }
  _Vnode.parseXml = function(xml,args){
    var i = 0;
    var prev = '',word = '',current,vnode;
    var building = false;
    var state = {
      tagNameing:false,//开始标签
      attrNameing:false,//属性名称
      attrValueing:false//属性值
    }
    function state_to(name){
      if(!name) {
        building = false;
        for(var key in state) state[key] = false;
      }else{
        building = true;
        for(var key in state) state[key] = (key === name);
      }
    }
    function buildNode(tagName){
      var node = new _Vnode(tagName);
      if(!current) {
        vnode = node;
      }else{
        current.appendChild(node);
      }
      current = node;
      word = '';
      state_to('attrNameing');
    }
    var attrName = '';
    while(i < xml.length){
      var addWord = false,now = xml.charAt(i);
      switch(now){
        case '<':
          if(!building) {
            if(word/*.replace(/\s/g,'')*/){
              var node = new _Vnode('');
              node.nodeType = 3;
              node.nodeValue = word;
              current.appendChild(node);
            }
            word = '';
            state_to('tagNameing');
          }else{
            addWord = true;
          }
          break;
        case '>':
          if(state.tagNameing) {
            if(word.charAt(0) === '/'){
              if(current && current.tagName === word.replace('/','')) {
                current = current.parentNode;
                word = '';
              }else{
                var parent = current.parentNode;
                parent.removeChild(current);
                current = parent;
                word = '<' + word + '>';
              }
            }else{
              buildNode(word);
            }
            state_to();
          }else if(state.attrValueing){
            if((word.charAt(0) === '"' || word.charAt(0) === "'") && word.charAt([word.length - 1]) === word.charAt(0)){
              current.setAttribute(attrName,word.replace(/^"/,'').replace(/^'/,'').replace(/"$/,'').replace(/'$/,''));
              state_to();
              word = '';
            }else{
              addWord = true;
            }
          }else if(state.attrNameing){
            attrName = word.replace(' ','');
            current.setAttribute(attrName,true);
            word = '';
            state_to();
          }else{
            addWord = true;
          }
          break;
        case '=':
          if(state.attrNameing) {
            attrName = word.replace(' ','');
            word = '';
            state_to('attrValueing');
          }else if(state.attrValueing && !word.replace(/\s/g,'')){
            //
          }else{
            addWord = true;
          }
          break;
        case ' ':
          if(state.tagNameing){
            if(word.charAt(0) !== '/'){
              if(/\w$/.test(word)){
                buildNode(word);
              }else{
                addWord = true;
              }
            }else{
              addWord = true;
            }
          }else if(state.attrValueing){
            if(word.replace(/\s/g,'')){
              if((word.charAt(0) === '"' || word.charAt(0) === "'") && word.charAt([word.length - 1]) === word.charAt(0)){
                current.setAttribute(attrName,word.replace(/^"/,'').replace(/^'/,'').replace(/"$/,'').replace(/'$/,''));
                state_to('attrNameing');
                word = '';
              }else{
                addWord = true;
              }
            }
          }else if(state.attrNameing){
            attrName = word.replace(' ','');
            current.setAttribute(attrName,true);
            state_to('attrValueing');
            word = '';
          }else{
            addWord = true;
          }
          break;
        default:
          if(state.attrValueing && !word.replace(/\s/g,'') && /\w/.test(now)){
            state_to('attrNameing');
          }
          addWord = true;
          break;
      }
      if(addWord) word += now;
      prev = now;
      i ++;
    }
    return vnode;
  }
  return _Vnode;
})()